package com.wstuo.common.jbpm.service;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.model.ActivityCoordinates;
import org.jbpm.api.task.Participation;
import org.jbpm.api.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.wstuo.common.noticeRule.dto.NoticeInfoDTO;
import com.wstuo.common.noticeRule.service.INoticeRuleService;
import com.wstuo.common.rules.DroolsFacade;
import com.wstuo.common.rules.drool.RulePathFile;
import com.wstuo.common.rules.drool.RulePathType;
import com.wstuo.common.security.dao.IOrganizationDAO;
import com.wstuo.common.security.dao.IUserDAO;
import com.wstuo.common.security.entity.Organization;
import com.wstuo.common.security.entity.User;
import com.wstuo.common.security.service.IUserInfoService;
import com.wstuo.common.security.utils.LanguageContent;
import com.wstuo.common.tools.dto.HistoryRecordDTO;
import com.wstuo.common.tools.service.IHistoryRecordService;
import com.wstuo.common.bpm.api.IBPI;
import com.wstuo.common.bpm.api.ICustomAssign;
import com.wstuo.common.bpm.dao.IProcessUseDAO;
import com.wstuo.common.bpm.dto.ActivityCoordinatesDTO;
import com.wstuo.common.bpm.dto.FlowActivityDTO;
import com.wstuo.common.bpm.dto.FlowPropertyDTO;
import com.wstuo.common.bpm.dto.FlowTaskDTO;
import com.wstuo.common.bpm.dto.HistoryTaskDTO;
import com.wstuo.common.bpm.dto.ProcessAssignDTO;
import com.wstuo.common.bpm.dto.ProcessDetailDTO;
import com.wstuo.common.bpm.dto.ProcessHandleDTO;
import com.wstuo.common.bpm.dto.ProcessHistoriesDTO;
import com.wstuo.common.bpm.dto.ProcessHistoriesQueryDTO;
import com.wstuo.common.bpm.dto.TaskDTO;
import com.wstuo.common.bpm.dto.TaskQueryDTO;
import com.wstuo.common.bpm.entity.ProcessUse;
import com.wstuo.common.bpm.service.IFlowPropertyService;
import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.exception.ApplicationException;
import com.wstuo.common.jbpm.IJbpmFacade;
import com.wstuo.common.jbpm.dao.IJbpmTaskDAO;
import com.wstuo.common.jbpm.dto.AssignDTO;
import com.wstuo.common.jbpm.entity.JbpmTask;
import com.wstuo.common.util.ObjectUtils;
import com.wstuo.common.util.StringUtils;

/**
 * business process instance implement class
 * @author wstuo
 *
 */
public class JbpmBPI implements IBPI {
	final static Logger LOGGER = Logger.getLogger(JbpmBPI.class);
	final static Map<String,String> AssignTypeI18n = new HashMap<String, String>(){
		{
			put("autoAssignee", "title.bpm.use.event.assign");
			put("dynamicAssignee", "label.bpm.isDynamicAssignee");
			put("variablesAssignee", "label.bpm.variablesAssignee");
			put("ruleAssignee", "lable.ruleAssignee");
		}
	};
	private DroolsFacade droolsFacade = new DroolsFacade();
	@Autowired
	private IJbpmFacade jbpmFacade;
	@Autowired
	private IJbpmTaskDAO jbpmTaskDAO;
	@Autowired
	private IProcessUseDAO processUseDAO;
	@Autowired
	private IFlowPropertyService flowPropertyService;
	@Autowired
	private IOrganizationDAO organizationDAO;
	@Autowired
	private IUserInfoService userInfoService;
	@Autowired
	private IUserDAO userDAO;
	@Autowired
	private INoticeRuleService noticeRuleService;
	@Autowired
	private IHistoryRecordService historyRecordService;
	
	@Transactional
	public PageDTO findPageProcessInstance(String processDefinitionId,
			int start, int limit) {
		return jbpmFacade.findInstances(processDefinitionId, start, limit);
	}

	@Transactional
	public PageDTO findPageHistoryProcessInstance(ProcessHistoriesQueryDTO dto,
			int start, int limit) {
		return jbpmFacade.findPageHistories(dto, start, limit);
	}
	
	@Transactional
	public List<ProcessDetailDTO> findProcessInstanceDetail(String pid) {
		return jbpmFacade.findProcessDetail(pid);
	}
	
	@Transactional
	public ProcessHistoriesDTO findHistoryProcessInstanceByPid(String pid) {
		return jbpmFacade.findHistoryProcessInstanceByPid(pid);
	}

	@Transactional
	public String startProcessById(String id, Map<String, Object> variables) {
		ProcessInstance pi = jbpmFacade.startProcessByDefinitionId(id, variables);
		return pi.getId();
	}

	@Transactional
	public String startProcessByKey(String key, Map<String, Object> variables) {
		ProcessInstance pi = jbpmFacade.startProcessByKey(key, variables);
		return pi.getId();
	}

	@Transactional
	public void endProcessInstance(String pid) {
		jbpmFacade.endProcessInstance(pid);
	}
	@Transactional
	public String startProcessByIdAndNextActivity(String id,
			Map<String, Object> variables) {
		ProcessInstance pi = jbpmFacade.startProcessByDefinitionId(id, variables);
		pi = jbpmFacade.signalNextExecution(pi);
		return pi.getId();
	}

	@Transactional
	public String startProcessByKeyAndNextActivity(String key,
			Map<String, Object> variables) {
		ProcessInstance pi = jbpmFacade.startProcessByKey(key, variables);
		pi = jbpmFacade.signalNextExecution(pi);
		return pi.getId();
	}

	@Transactional
	public boolean isEnded(String pid) {
		return jbpmFacade.isEnded(pid);
	}

	@Transactional
	public InputStream getProcessImage(String processDefinitionId) {
		return jbpmFacade.getProcessImage(processDefinitionId);
	}
	@Transactional
	public String getProcessXml(String processDefinitionId) {
		return jbpmFacade.getProcessXml(processDefinitionId);
	}

	public InputStream getProcessImageByDeploymentId(String deploymentId) {
		return jbpmFacade.getProcessImageByDeploymentId(deploymentId);
	}

	@Transactional
	public PageDTO findPageGroupTasks(String userId, int page, int limit) {
		/*List<Task> groupTasks = jbpmFacade.findGroupTaskDtos(userId);
		int totalSize = groupTasks.size();
		PageDTO p = new PageDTO();
        p.setTotalSize(totalSize);

        List<TaskDTO> dtos = new ArrayList<TaskDTO>();*/

        int start = (page - 1) * limit;
        /*int end = ( limit * page ) - 1;
        if (end >= totalSize){
            end = totalSize - 1;
        }
        for(int i=start;i<=end;i++){
        	TaskDTO dto = jbpmFacade.task2Dto(groupTasks.get(i));
            dtos.add(dto);
        }
        p.setData( dtos );
        p.setTotalSize(totalSize);*/
		return jbpmFacade.findGroupTaskDtos(userId,start,limit);
	}
	
	@Transactional
	public PageDTO findHistoryTask(String pid,String assignee,int start,int limit) {
		return jbpmFacade.findHistoryTask(pid,assignee,start,limit);
	}

	/**
	 * 查找当前实例最后处理完成的历史任务
	 * @param processInstanceId 实例ID
	 * @return 最后处理完成的历史任务
	 */
	public HistoryTaskDTO findLastCompleteHistoryActivityInstance(String processInstanceId){
		
		return jbpmFacade.findLastCompleteHistoryActivityInstance(processInstanceId);
	}
	
	@Transactional
	public PageDTO findPagePersonalTasks(String userId, int start, int limit) {
		return jbpmFacade.findPersonalTasks(userId, start, limit);
	}
	
	@SuppressWarnings("unchecked")
	@Transactional
	public PageDTO findJbpmTaskPager(TaskQueryDTO queryDTO,String sidx,String sord,int start,int rows) {
		PageDTO p =jbpmTaskDAO.findJbpmTaskPager(queryDTO,sidx,sord,start,rows);
		List<JbpmTask> listEntity=p.getData();
		List<TaskQueryDTO> listDto = new ArrayList<TaskQueryDTO>();
		for(JbpmTask entity:listEntity){
			TaskQueryDTO dto = new TaskQueryDTO();
			jbpmTaskEntity2Dto(entity,dto);
			listDto.add(dto);
		}
		p.setData(listDto);
       return p;
	}
	private void jbpmTaskEntity2Dto(JbpmTask entity,TaskQueryDTO queryDTO){
		TaskQueryDTO.entity2dto(entity, queryDTO);
		if(entity.getId()!=null){
			queryDTO.setVariables(jbpmFacade.getVariablesByTaskId(entity.getId().toString()));
		}
	}

	@Transactional
	public Integer countGroupTasks(String userId) {
		List<Task> groupTasks = jbpmFacade.findGroupTasks(userId);
		return groupTasks.size();
	}

	@Transactional
	public Integer countPersonalTasks(String userId) {
		return jbpmFacade.countPersonalTasks(userId);
	}

	@Transactional
	public Integer countGetPendingTasks(String userId) {
		return jbpmFacade.countGetPendingTasks(userId);
	}
	
	@Transactional
	public Integer countMyProcessedTask(String userId) {
		return jbpmFacade.countMyProcessedTask(userId);
	}

	@Transactional
	public void assignTask(String taskId, String username) {
		jbpmFacade.assignTask(taskId, username);
	}

	
	
	public void deleteTask(String taskId) {
		jbpmFacade.deleteTask(taskId);
	}

	@Transactional
	public void addTaskParticipatingGroup(String taskId, String groupId,
			String participationType) {
		jbpmFacade.addTaskParticipatingGroup(taskId, groupId, participationType);
	}
	
	@Transactional
	public void addTaskParticipatingUser(String taskId, String userId,
			String participationType) {
		jbpmFacade.addTaskParticipatingUser(taskId, userId, participationType);
	}

	@Transactional
	public void assignTaskByPid(String pid, String assignee) {
		List<ProcessDetailDTO> pdDTOs = findProcessInstanceDetail(pid);
    	if(pdDTOs!=null){
    		for(ProcessDetailDTO pdDTO : pdDTOs){
    			List<FlowTaskDTO> ftDTOs = pdDTO.getFlowTaskDTO();
        		for(FlowTaskDTO ft : ftDTOs){
        			assignTask(ft.getTaskId(), assignee);
        		}
    		}
    	}
	}

	@Transactional
	public void addTaskParticipatingGroupByPid(String pid, String groupId) {
		List<ProcessDetailDTO> pdDTOs = findProcessInstanceDetail(pid);
    	if(pdDTOs!=null){
    		for(ProcessDetailDTO pdDTO : pdDTOs){
    			List<FlowTaskDTO> ftDTOs = pdDTO.getFlowTaskDTO();
        		for(FlowTaskDTO ft : ftDTOs){
        			addTaskParticipatingGroup(ft.getTaskId(), groupId, Participation.CANDIDATE);
        		}
    		}
    	}
	}
	
	@Transactional
	public void addTaskParticipatingUserByPid(String pid, String userId) {
		List<ProcessDetailDTO> pdDTOs = findProcessInstanceDetail(pid);
    	if(pdDTOs!=null){
    		for(ProcessDetailDTO pdDTO : pdDTOs){
    			List<FlowTaskDTO> ftDTOs = pdDTO.getFlowTaskDTO();
        		for(FlowTaskDTO ft : ftDTOs){
        			addTaskParticipatingUser(ft.getTaskId(), userId, Participation.CANDIDATE);
        		}
    		}
    	}
	}
	

	@Transactional
	public String getProcessDefinitionIdByPid(String pid) {
		String finitionId = null;
		ProcessHistoriesQueryDTO qdto = new ProcessHistoriesQueryDTO();
		qdto.setProcessInstanceId(pid);
		PageDTO p = jbpmFacade.findPageHistories(qdto, 0, 1);
		if(p!=null && p.getData()!=null && p.getData().size()>0){
			ProcessHistoriesDTO ph = (ProcessHistoriesDTO)p.getData().get(0);
			finitionId = ph.getProcessDefinitionId();
		}
		return finitionId;
	}

	@Transactional
	public String getActivityNameByPid(String pid) {
		return jbpmFacade.getActivityNameByPid(pid);
	}

	@Transactional
	public void completeTask(String taskId, String next,
			Map<String, Object> variables) {
		jbpmFacade.completeTask(taskId, next, variables);
	}

	@Transactional
	public void completeTask(String taskId) {
		jbpmFacade.completeTask(taskId);
	}
	
	@Transactional
	public void completeTask(String userId, String taskId, String next,
			Map<String, Object> variables) {
		jbpmFacade.completeTask(userId, taskId, next, variables);
	}
	
	@Transactional
	public void completeTask(String taskId, String next) {
		jbpmFacade.completeTask(taskId, next);
	}

	@Transactional
	public void completeTask(String userId, String taskId, String next) {
		jbpmFacade.completeTask(userId, taskId, next);
	}
	
	@Transactional
	public void setInstanceVariable(String pid, String name, Object value) {
		jbpmFacade.setInstanceVariable(pid, name, value);
	}

	@Transactional
	public void setInstanceVariables(String pid, Map<String, Object> map) {
		jbpmFacade.setInstanceVariables(pid, map);
	}
	
	@Transactional
	public void setInstanceVariables(String processInstanceId, String name,
			Object value) {
		jbpmFacade.setInstanceVariable(processInstanceId, name, value);
	}
	@Transactional
	public Object getInstanceVariables(String pid, String variableName) {
		return jbpmFacade.getInstanceVariables(pid, variableName);
	}

	@Transactional
	public Set<String> getInstanceVariableNames(String pid) {
		return jbpmFacade.getInstanceVariableNames(pid);
	}

	@Transactional
	public Map<String, Object> getInstanceVariables(String pid,
			Set<String> variableNames) {
		return jbpmFacade.getInstanceVariables(pid, variableNames);
	}

	@Transactional
	public void setTaskVariables(String taskId, Map<String, Object> variables) {
		jbpmFacade.setTaskVariables(taskId, variables);
	}

	@Transactional
	public Object getTaskVariable(String taskId, String variableName) {
		return jbpmFacade.getTaskVariable(taskId, variableName);
	}

	@Transactional
	public Set<String> getTaskVariableNames(String taskId) {
		return jbpmFacade.getTaskVariableNames(taskId);
	}

	@Transactional
	public Map<String, Object> getTaskVariables(String taskId,
			Set<String> variableNames) {
		return jbpmFacade.getTaskVariables(taskId, variableNames);
	}

	@Transactional
	public ActivityCoordinatesDTO getActivityCoordinates(String pid) {
		ProcessInstance pi = jbpmFacade.getInstanceById(pid);
		ActivityCoordinatesDTO acDTO = new ActivityCoordinatesDTO();
		if(pi!=null){
			ActivityCoordinates ac = jbpmFacade.getActivityCoordinatesByInstance(pi);
			ActivityCoordinatesDTO.entity2dto(ac, acDTO);
		}
		
		return acDTO;
	}
	
	@Transactional
	public List<ActivityCoordinatesDTO> getHistoryActivityCoordinates(String pid){
		List<ActivityCoordinatesDTO> activityCoordinatesDTOs = jbpmFacade.getHistoryActivityCoordinatesByInstance(pid);
		return activityCoordinatesDTOs;
	}
	
	/**
	 * 根据PID获取流程出口
	 * @param pid
	 * @return
	 */
	@Transactional
	public Set<String> getOutcomesByPid(String pid){
		return jbpmFacade.getOutcomes(pid);
	};
	
	@Transactional
	public FlowPropertyDTO findProcessDefinitionActivity(String deploymentId) {
		return null;
	}

	@Transactional
	public String getNextActivity(String pid, String activityName,
			String outcome) {
		return jbpmFacade.getNextActivity(pid, activityName, outcome);
	}

	@Transactional
	public FlowActivityDTO findFlowActivityByPidTaskName(String pid,
			String taskName) {
		return null;
	}

	@Transactional
	public void deleteProcessInstance(String pid) {
		if(!isEnded(pid))
		jbpmFacade.deleteProcessInstance(pid);
	}

	@Transactional
	public void deleteProcessInstanceCascade(String pid) {
		if(!isEnded(pid))
		jbpmFacade.deleteProcessInstanceCascade(pid);
	}
	@Transactional
	public List<String> findAllTaskByPid(String pid){
		
		ProcessInstance pi = jbpmFacade.getInstanceById(pid);
        String nextActivityName = jbpmFacade.getActivityNamesByInstance(pi).iterator(  ).next(  );
        List<Task> tasks = jbpmFacade.findTaskByPidActivityName(pid,nextActivityName);
        List<String> taskIds = new ArrayList<String>();
        for(Task tk : tasks){
        	taskIds.add(tk.getId());
        }
		return taskIds;
	}
	
	/**
	 * 获取流程定义
	 * @param processDefinitionId
	 * @param module
	 * @return
	 */
	public String getProcessDefinitionId(String processDefinitionId,String module){
		if(!StringUtils.hasText(processDefinitionId)) {// 使用默认流程
			ProcessUse pree = processUseDAO.findUniqueBy("useName", "processUse");
			if (pree != null) {
				if(("itsm.problem").equals(module)){
					processDefinitionId = pree.getProblemProcessDefinitionId();
				}else if(("itsm.change").equals(module)){
					processDefinitionId = pree.getChangeProcessDefinitionId();
				}else if(("itsm.release").equals(module)){
					processDefinitionId = pree.getReleaseProcessDefinitionId();
				}else{
					processDefinitionId = pree.getRequestProcessDefinitionId();
				}
			}else{
				throw new ApplicationException("ERROR_PROCESS_DEFINDED", "流程没找到！");
			}
		}
		return processDefinitionId;
	}
	
	@SuppressWarnings("unchecked")
	@Transactional
	public String startFlowInstance(String module ,String processDefinitionId , Object bean) {
		//规则匹配到了流程 Tan 20140917
		processDefinitionId = getProcessDefinitionId(processDefinitionId, module);
		
		Map<String,Object> map = (Map<String,Object>)ObjectUtils.getFieldValueByName(bean, "piv");
		for(String key : map.keySet()){
			map.put(key, ObjectUtils.getFieldValueByName(bean, key)); 
		}
		String pid = this.startProcessByIdAndNextActivity(processDefinitionId, map);
		return pid;
	}
	
	@SuppressWarnings("unchecked")
	@Transactional
	public void setInstanceVariables(String pid , Object bean) {
		Map<String, Object> mapInfo = new HashMap<String, Object>();
		try {
			mapInfo = BeanUtils.describe(bean);
		} catch (IllegalAccessException e) {
			LOGGER.error(e);
		} catch (InvocationTargetException e) {
			LOGGER.error(e);
		} catch (NoSuchMethodException e) {
			LOGGER.error(e);
		}
		jbpmFacade.setInstanceVariables(pid, mapInfo);
	}
	
	@Transactional
	public Object assignTask(ProcessHandleDTO phDTO,Object bean){
		LanguageContent lc = LanguageContent.getInstance();
		if (phDTO.getAssigneeNo() != null && phDTO.getAssigneeNo() > 0) {
			String pid = phDTO.getPid();
			User assignee = userDAO.findById(phDTO.getAssigneeNo());
			String fullName = "";
			if (assignee != null) {
				assignTaskByPid(pid, assignee.getLoginName());
				fullName = assignee.getFullName();
			}
			if(isUpdateEventAssign(pid)){
				try {
					BeanUtils.setProperty(bean, "taskAssigneeNo", assignee.getUserId());
				} catch (IllegalAccessException e) {
					LOGGER.error("BeanUtils setProperty Error"+e.getMessage());
				} catch (InvocationTargetException e) {
					LOGGER.error("BeanUtils setProperty Error"+e.getMessage());
				}
			}
			//历史记录
			phDTO.setRemark(lc.getContent("notice.assignTechnician") + "：" +  fullName + "<br/>" + lc.getContent("label.role.roleMark") + ": " + phDTO.getRemark());
			//历史记录动作
			String logTitle = getitsmbest(phDTO.getHandleType(),lc);
			logTitle = setHistoryLogTitle(phDTO, lc, logTitle);
			saveHistoryRecord(phDTO, logTitle);
			
			//获取当前流程节点属性
			String activityName = getActivityNameByPid(phDTO.getPid());
			String processDefinitionId = this.getProcessDefinitionIdByPid(phDTO.getPid());
			FlowActivityDTO flowActivityDTO = flowPropertyService.findFlowActivity(processDefinitionId, new String[] { "task", "foreach", "join" }, activityName);
			assigeNotice(bean, flowActivityDTO, assignee, null,phDTO.getModule(),phDTO.getEmailAddress(),pid);
		}
		return bean;
	}
	
	/**
	 * 根据传入字符串返回相应国际化文本
	 */
	private String getitsmbest(String title,LanguageContent lc){
		if(lc != null && "TaskTake".equals(title)){
			title = lc.getContent("title.bpm.task.take");
		}
		return title;
	}
	/**
	 * 根据流程动作设置历史记录动作
	 * @param phDTO
	 * @param lc
	 * @param logTitle
	 * @return
	 */
	private String setHistoryLogTitle(ProcessHandleDTO phDTO,
			LanguageContent lc, String logTitle) {
		if("TaskReAssigne".equals(phDTO.getHandleType())){
			logTitle = lc.getContent("title.bpm.task.assign");
		}
		return logTitle;
	}
	
	private void getAssignOrgOrUser(AssignDTO assignDTO , 
			ProcessHandleDTO phDTO,Object bean,FlowActivityDTO flowActivityDTO,
			ICustomAssign customAssign){
		//请求人
		String createdByNo=null;
		//指派的用户
		String technicianNo=null;
		//指派的组
		String assigneeGroupNo=null;
		Organization group = null;
		User assignee = null;
		try {
			//将出口及活动名称设置到Bean中
			BeanUtils.setProperty(bean, "outcome", phDTO.getOutcome());
			BeanUtils.setProperty(bean, "activityName", phDTO.getActivityName());
			//获取创建人、指派技术员、指派组的ID
			createdByNo = BeanUtils.getProperty(bean , "createdByNo");
			technicianNo = BeanUtils.getProperty(bean , "technicianNo");
			assigneeGroupNo = BeanUtils.getProperty(bean , "assigneeGroupNo");
		} catch (IllegalAccessException e1) {
			LOGGER.error("Assign task get property createdByNo/technicianNo/assigneeGroupNo error"+e1.getMessage());
		} catch (InvocationTargetException e1) {
			LOGGER.error("Assign task get property createdByNo/technicianNo/assigneeGroupNo error"+e1.getMessage());
		} catch (NoSuchMethodException e1) {
			LOGGER.error("Assign task get property createdByNo/technicianNo/assigneeGroupNo error"+e1.getMessage());
		}
		
		try {
			BeanUtils.setProperty(bean, "technicianNo", null);
			BeanUtils.setProperty(bean, "assigneeGroupNo", null);
		} catch (IllegalAccessException e1) {
			LOGGER.error("set property technicianNo/assigneeGroupNo is null error"+e1.getMessage());
		} catch (InvocationTargetException e1) {
			LOGGER.error("set property technicianNo/assigneeGroupNo is null error"+e1.getMessage());
		}
		
		//指派方式
		String assignType=flowActivityDTO.getAssignType();
		//流程规则匹配
		if (StringUtils.hasText(flowActivityDTO.getMatchRuleIds())) {//流程规则
			Set<String> setrule = transPackageName(flowActivityDTO.getMatchRuleIds());
			//任务节点可能会设置多个规则包，所以只能循环匹配
			for (String packageName : setrule) {
				if(phDTO.getModule().equals("change")){
					droolsFacade.matchRule(bean, new String[] { packageName },RulePathType.ChangeWorkFlow.getValue(),RulePathFile.URL_SETCHANGEWORKFLOWRULESOURCE.getValue());
				}else{
					droolsFacade.matchRule(bean, new String[] { packageName },RulePathType.RequestWorkFlow.getValue(),RulePathFile.URL_SETREQUESTWORKFLOWRULESOURCE.getValue());
				}
			}
		}
		
		if ("variablesAssignee".equals(assignType)) {
			String variablesAssigneeType = flowActivityDTO.getVariablesAssigneeType();
			//变量指派
			assignee = userInfoService.setVariablesAssignee(assignee, variablesAssigneeType, Long.parseLong(createdByNo), Long.parseLong(technicianNo), flowActivityDTO.getVariablesAssigneeGroupNo());
			
			if(flowActivityDTO.getVariablesAssigneeGroupNo()!=null){
				group = organizationDAO.findById(flowActivityDTO.getVariablesAssigneeGroupNo());
			}
			//规则指派	
		}else if("ruleAssignee".equals(assignType)){
			String automaticallyAssigned ="false";
			try {
				//任务指派的用户
				technicianNo = BeanUtils.getProperty(bean , "taskAssigneeNo");
				//指派的组
				assigneeGroupNo = BeanUtils.getProperty(bean , "taskassigneeGroupNo");
				//自动指派
				automaticallyAssigned =BeanUtils.getProperty(bean ,"automaticallyAssigned");
			} catch (IllegalAccessException e) {
				LOGGER.error("Rule assign get property technicianNo/assigneeGroupNo/automaticallyAssigned error"+e.getMessage());
			} catch (InvocationTargetException e) {
				LOGGER.error("Rule assign get property technicianNo/assigneeGroupNo/automaticallyAssigned error"+e.getMessage());
			} catch (NoSuchMethodException e) {
				LOGGER.error("Rule assign get property technicianNo/assigneeGroupNo/automaticallyAssigned error"+e.getMessage());
			}
			
			if(technicianNo!=null){
				assignee = userDAO.findById(Long.parseLong(technicianNo));
			}
			if(assigneeGroupNo!=null){
				group = organizationDAO.findById(Long.parseLong(assigneeGroupNo));
			}
			//自定义指派规则
			if("true".equals(automaticallyAssigned)){
				Object obj = customAssign.execute();
				if(obj!=null){
					assignee = (User)obj;
				}
			}
		//其他均自动指派	
		}else{
			/*if(StringUtils.hasText(phDTO.getTaskId())){
				Task task = jbpmFacade.getTask(phDTO.getTaskId());
				if(task!=null){
					assignee = userDAO.findUniqueBy("loginName", task.getAssignee());
				}
			}else{
				if(technicianNo!=null){
					assignee = userDAO.findById(Long.parseLong(technicianNo));
				}
			}*/
			if(StringUtils.hasText(flowActivityDTO.getCandidateUsersNo())){
				try {
					assignee = userDAO.findById(Long.parseLong(flowActivityDTO.getCandidateUsersNo()));
				} catch (Exception e) {
					e.printStackTrace();
				}
				
			}else{
				if(technicianNo!=null){
					assignee = userDAO.findById(Long.parseLong(technicianNo));
				}
			}
			if(StringUtils.hasText(flowActivityDTO.getCandidateGroupsNo())){
				try {
					group = organizationDAO.findById(Long.parseLong(flowActivityDTO.getCandidateGroupsNo()));
				} catch (Exception e) {
					// TODO: handle exception
				}
				
			}else if(assigneeGroupNo!=null){
				group = organizationDAO.findById(Long.parseLong(assigneeGroupNo));
			}
		}
		//回退给上次任务指派的技术员
		if(flowActivityDTO.getIsFallbackToTechnician()){
			ProcessInstance pi = jbpmFacade.getInstanceById(phDTO.getPid());
			String assigneeLoginName = jbpmFacade.findAssigneeByHistoryTask(pi,flowActivityDTO.getActivityName());
			if(StringUtils.hasText(assigneeLoginName)){
				assignee = userDAO.findUniqueBy("loginName", assigneeLoginName);
			}
		}
		assignDTO.setGroup(group);
		assignDTO.setAssignee(assignee);
	}
	
	
	private void assignTaskSaveHistoryRecord(ProcessHandleDTO phDTO,String assignType ,Organization group , User assignee){
		if(StringUtils.hasText(phDTO.getOutcome())&&!phDTO.getIsApproversMember()){
			if(StringUtils.hasText(assignType) && (group!=null || assignee!=null)){
				//指派历史记录
				LanguageContent lc = LanguageContent.getInstance();
				//格式：[XX指派方式]:XX技术员,XX组
				StringBuffer sb = new StringBuffer();
				sb.append("["+lc.getContent(AssignTypeI18n.get(assignType))+"]:");
				if(assignee!=null){
					sb.append(assignee.getFullName());
				}
				if(group!=null){
					if(assignee!=null){
						sb.append(",");
					}
					sb.append(group.getOrgName());
				}
				phDTO.setRemark(phDTO.getRemark()+"\r\n"+sb.toString());
			}
			// 保存历史记录
			saveHistoryRecord(phDTO,phDTO.getOutcome());
		}
	}
	private void assignTask(AssignDTO assignDTO , String pid , Object bean){
		User assignee = assignDTO.getAssignee();
		Organization group = assignDTO.getGroup();
		List<String> candidateGroupsNo =  assignDTO.getCandidateGroupsNo();
		List<String> candidateUsersNo = assignDTO.getCandidateUsersNo();
		if (assignee != null) {
			assignTaskByPid(pid, assignee.getLoginName());
		} else if (group != null) {
			addTaskParticipatingGroupByPid(pid, "Group_" + group.getOrgNo());
		} else {//候补组
			assignTaskByPid(pid, null);
			if(candidateUsersNo!=null && candidateUsersNo.size()>0){//候选人
				for (String userNo : candidateUsersNo) {
					addTaskParticipatingUserByPid(pid, userNo);
				}
			}
			if(candidateGroupsNo!=null && candidateGroupsNo.size()>0){//候选组
				for (String groupNo : candidateGroupsNo) {
					addTaskParticipatingGroupByPid(pid, "Group_" + groupNo);
				}
			}
		}
		//设置已指派
		try {
			if(assignee!=null){
				BeanUtils.setProperty(bean, "taskAssigneeNo", assignee.getUserId());
			}
			if(group!=null){
				BeanUtils.setProperty(bean, "taskassigneeGroupNo", group.getOrgNo());
			}
		} catch (IllegalAccessException e) {
			LOGGER.error("BeanUtils setProperty Error"+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("BeanUtils setProperty Error"+e.getMessage());
		}
	}
	
	@Transactional
	public ProcessAssignDTO findProcessAssignDTO(ProcessHandleDTO phDTO, Object bean , ICustomAssign customAssign){
		ProcessAssignDTO processAssignDTO = new ProcessAssignDTO();
		//任务指派
		String pid = phDTO.getPid();
		String processDefinitionId = this.getProcessDefinitionIdByPid(pid);
		//获取当前流程节点属性
		String activityName = getActivityNameByPid(pid);
		FlowActivityDTO flowActivityDTO = flowPropertyService.findFlowActivity(processDefinitionId, new String[] { "task", "foreach", "join" }, activityName);
		//待指派用户或组
		AssignDTO assignDTO = new AssignDTO();
		if(!phDTO.getIsOpenProcess()){
			//获取下一步流程节点属性
			String nextActivityName = getNextActivity(phDTO.getPid(), phDTO.getTaskName(), phDTO.getOutcome());
			FlowActivityDTO nextFlowActivityDTO = flowPropertyService.findFlowActivity(processDefinitionId, new String[]{"task","foreach","join"}, nextActivityName);
			this.getAssignOrgOrUser(assignDTO, phDTO,bean,nextFlowActivityDTO,customAssign);
			processAssignDTO.setNextFlowActivityDTO(nextFlowActivityDTO);
		}else{//开启流程使用的是第一个节点的属性
			this.getAssignOrgOrUser(assignDTO, phDTO,bean,flowActivityDTO,customAssign);
			processAssignDTO.setNextFlowActivityDTO(flowActivityDTO);
		}
		
		if(assignDTO.getAssignee()!=null){
			processAssignDTO.setAssigneeId(assignDTO.getAssignee().getUserId());
			processAssignDTO.setAssigneeName(assignDTO.getAssignee().getFullName());
		}
		if(assignDTO.getGroup()!=null){
			processAssignDTO.setGroupId(assignDTO.getGroup().getOrgNo());
			processAssignDTO.setGroupName(assignDTO.getGroup().getOrgName());
		}
		processAssignDTO.setFlowActivityDTO(flowActivityDTO);
		
		return processAssignDTO;
	}
	
	
	//待指派用户或组
	private void getAssignDTO(ProcessHandleDTO phDTO,AssignDTO assignDTO ,FlowActivityDTO flowActivityDTO){
		if(phDTO.getAssigneeNo()!=null){
			assignDTO.setAssignee(userDAO.findById(phDTO.getAssigneeNo()));
		}
		if(phDTO.getGroupNo()!=null){
			assignDTO.setGroup(organizationDAO.findById(phDTO.getGroupNo()));
		}
		if(flowActivityDTO.getCandidateGroupsNo()!=null){
			assignDTO.setCandidateGroupsNo(Arrays.asList(flowActivityDTO.getCandidateGroupsNo().split(",")));
		}
		if(flowActivityDTO.getCandidateUsersNo()!=null){
			assignDTO.setCandidateUsersNo(Arrays.asList(flowActivityDTO.getCandidateUsersNo().split(";")));
		}
	}
	//根据流程规则获取Bean
	private Object getBeanByFlowRule(ProcessHandleDTO phDTO,Object bean,FlowActivityDTO flowActivityDTO){
		try {
			BeanUtils.setProperty(bean, "technicianNo", null);
			BeanUtils.setProperty(bean, "assigneeGroupNo", null);
		} catch (IllegalAccessException e1) {
			LOGGER.error("set property technicianNo/assigneeGroupNo is null error"+e1.getMessage());
		} catch (InvocationTargetException e1) {
			LOGGER.error("set property technicianNo/assigneeGroupNo is null error"+e1.getMessage());
		}
		//流程规则匹配
		if (StringUtils.hasText(flowActivityDTO.getMatchRuleIds())) {//流程规则
			Set<String> setrule = transPackageName(flowActivityDTO.getMatchRuleIds());
			//任务节点可能会设置多个规则包，所以只能循环匹配
			for (String packageName : setrule) {
				if(phDTO.getModule().equals("change")){
					droolsFacade.matchRule(bean, new String[] { packageName },RulePathType.ChangeWorkFlow.getValue(),RulePathFile.URL_SETCHANGEWORKFLOWRULESOURCE.getValue());
				}else{
					droolsFacade.matchRule(bean, new String[] { packageName },RulePathType.RequestWorkFlow.getValue(),RulePathFile.URL_SETREQUESTWORKFLOWRULESOURCE.getValue());
				}
			}
		}
		return bean;
	}
	
	@Transactional
	public Object assignTask(ProcessHandleDTO phDTO,Object bean , ICustomAssign customAssign) {
		//任务指派
		String pid = phDTO.getPid();
		//获取当前流程节点属性
		String activityName = getActivityNameByPid(pid);
		String processDefinitionId = this.getProcessDefinitionIdByPid(pid);
		FlowActivityDTO flowActivityDTO = flowPropertyService.findFlowActivity(processDefinitionId, new String[] { "task", "foreach", "join" }, activityName);
		//待指派用户或组
		AssignDTO assignDTO = new AssignDTO();
		///////////获取指派组或用户/////////////
		this.getAssignDTO(phDTO,assignDTO,flowActivityDTO);
		
		///////////根据流程规则获取Bean////////
		this.getBeanByFlowRule(phDTO, bean, flowActivityDTO);
		
		///////////进行任务指派/////////////
		this.assignTask(assignDTO, pid , bean );
		
		///////////保存历史记录/////////////
		this.assignTaskSaveHistoryRecord(phDTO , flowActivityDTO.getAssignType() , assignDTO.getGroup() , assignDTO.getAssignee() );
		
		///////////指派通知/////////////
		this.assigeNotice(bean, flowActivityDTO, assignDTO.getAssignee(), assignDTO.getGroup(),phDTO.getModule(),phDTO.getEmailAddress(),pid);
		
		return bean;
	}
	/**
	 * 转换匹配的规则包名称
	 * @param matchRuleIds
	 * @return
	 */
	private Set<String> transPackageName(String matchRulePackages){
		Set<String> packageNames = new HashSet<String>();
		String[] temp = matchRulePackages.split(",");
		for (String packageName : temp) {
			packageNames.add(packageName);//"com.drools.drl."+
		}
		return packageNames;
	}
	/**
	 * 设置历史记录
	 * @param bean
	 * @param module
	 */
	private Object setHistoryRecordDTO(Object bean,String module){
		String eno = null;
		try {
			//获取创建人、指派技术员、指派组的ID
			eno = BeanUtils.getProperty(bean , "eno");
		} catch (IllegalAccessException e1) {
			LOGGER.error("Assign task get property eno error"+e1.getMessage());
		} catch (InvocationTargetException e1) {
			LOGGER.error("Assign task get property eno error"+e1.getMessage());
		} catch (NoSuchMethodException e1) {
			LOGGER.error("Assign task get property eno error"+e1.getMessage());
		}
		HistoryRecordDTO historyRecordDTO = new HistoryRecordDTO();
		historyRecordDTO.setEno(Long.parseLong(eno));
		historyRecordDTO.setEventType("itsm."+module);
		List<HistoryRecordDTO> historyRecordsDTO = historyRecordService.findAllHistoryRecord(historyRecordDTO);
		try {
			BeanUtils.setProperty(bean, "historyRecordDTO", historyRecordsDTO);
		} catch (IllegalAccessException e) {
			LOGGER.error("BeanUtils setProperty Error"+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("BeanUtils setProperty Error"+e.getMessage());
		}
		return bean;
	}
	/**
	 * 通知
	 * @param bean
	 * @param pid
	 * @param createdByNo
	 * @param flowActivityDTO
	 * @param assignee
	 * @param group
	 */
	private void assigeNotice(Object bean,FlowActivityDTO flowActivityDTO , User assignee , Organization group,String module,String emailAddress,String pid){
		// 对应的通知规则
		NoticeInfoDTO noticeInfoDto = new NoticeInfoDTO();
		noticeInfoDto.setNoticeRuleNo(module+"FlowActionNotice");
		bean = setHistoryRecordDTO(bean, module);
		noticeInfoDto.setVariables(bean);
		
		String createdByNo = null;
		try {
			//获取创建人、指派技术员、指派组的ID
			createdByNo = BeanUtils.getProperty(bean , "createdByNo");
		} catch (IllegalAccessException e1) {
			LOGGER.error("Assign task get property createdByNo error"+e1.getMessage());
		} catch (InvocationTargetException e1) {
			LOGGER.error("Assign task get property createdByNo error"+e1.getMessage());
		} catch (NoSuchMethodException e1) {
			LOGGER.error("Assign task get property createdByNo error"+e1.getMessage());
		}
		
		// 请求人
		if(createdByNo!=null){
			User user = userDAO.findById(Long.parseLong(createdByNo));
			noticeInfoDto.setRequester(user);
		}
		// 技术员
		if(assignee!=null){
			noticeInfoDto.setAssignTechnician(assignee);
			//邮件流程处理
			if(flowActivityDTO.getMailHandlingProcess()){
				// 邮件处理流程
				FlowTaskDTO flowTaskDto = new FlowTaskDTO();
				List<ProcessDetailDTO> processDetailDTO = this.findProcessInstanceDetail(pid);
				for (ProcessDetailDTO pdd : processDetailDTO) {
					for (FlowTaskDTO fd : pdd.getFlowTaskDTO()) {
						flowTaskDto = fd;
					}
				}
				noticeRuleService.sendMailHandlingProcess(assignee, bean, flowTaskDto, module);
			}
		}
		
		List<Organization> orgs = new ArrayList<Organization>();
		// 要通知的机构
		if(group!=null){
			orgs.add(group);
			noticeInfoDto.setAssignOrg(group);
		}
		
		noticeInfoDto.setEmailAddress(emailAddress);
		
		if(flowActivityDTO.getTaskAssigneeUserNotice() && !flowActivityDTO.getTaskAssigneeGroupNotice()){
			List<User> userList = new ArrayList<User>();
			userList.add(assignee);
			noticeInfoDto.setNoticeUsers(userList);
			noticeRuleService.commonNotice(noticeInfoDto);
		}else if(!flowActivityDTO.getTaskAssigneeUserNotice() && flowActivityDTO.getTaskAssigneeGroupNotice()){
			noticeInfoDto.setNoticeOrgs(orgs);
			noticeRuleService.commonNotice(noticeInfoDto);
		}else if(flowActivityDTO.getTaskAssigneeUserNotice() && flowActivityDTO.getTaskAssigneeGroupNotice()){
			List<User> userList = new ArrayList<User>();
			userList.add(assignee);
			noticeInfoDto.setNoticeOrgs(orgs);
			noticeInfoDto.setNoticeUsers(userList);
			noticeRuleService.commonNotice(noticeInfoDto);
		}
		// 流程到此节点时通知
		if (StringUtils.hasText(flowActivityDTO.getNoticeRuleIds())) {
			String[] ids = flowActivityDTO.getNoticeRuleIds().split(",");
			for (String str : ids) {
				if (StringUtils.hasText(str.trim())) {
					Long noticeRuleId = Long.parseLong(str.trim());
					noticeInfoDto.setNoticeRuleId(noticeRuleId);
					noticeInfoDto.setNoticeRuleNo(null);
					noticeRuleService.commonNotice(noticeInfoDto);
				}
			}
		}
	}
	
	
	/**
	 * 保留流程处理历史记录
	 * @param phDTO
	 */
	@Transactional
	private void saveHistoryRecord(ProcessHandleDTO phDTO,String title) {
		HistoryRecordDTO hrDTO = new HistoryRecordDTO();
		hrDTO.setEventType("itsm."+phDTO.getModule());
		hrDTO.setOperator(phDTO.getOperator());
		hrDTO.setLogTitle(title);
		hrDTO.setLogDetails(phDTO.getRemark());
		hrDTO.setCreatedTime(new Date());
		hrDTO.setEno(phDTO.getEno());
		historyRecordService.saveHistoryRecord(hrDTO);
	}
	
	/**
	  * 是否需要更新业务数据指派
	  * @param pid
	  * @return 是否需要指派结果
	  */
	public boolean isUpdateEventAssign(String pid) {
		//获取当前流程节点属性
		String activityName = getActivityNameByPid(pid);
		String processDefinitionId = this.getProcessDefinitionIdByPid(pid);
		FlowActivityDTO flowActivityDTO = flowPropertyService.findFlowActivity(processDefinitionId, new String[] { "task", "foreach", "join" }, activityName);
		return flowActivityDTO.getIsUpdateEventAssign();
	}
	
	 /**
	  * 查询下一活动类型
	  * @param pid 实例ID
	  * @param activityName 活动名
	  * @param outcome 出口
	  * @return 下一活动类型
	  */
	public String getNextActivityType(String pid, String activityName, String outcome) {
		// TODO Auto-generated method stub
		return jbpmFacade.getNextActivityType(pid, activityName, outcome);
	}

	
	
	
	
}
